package com.znsd.zl.sys.sms.utils;

import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.znsd.zl.exception.RRException;
import com.znsd.zl.sys.commons.utils.RedisUtils;
import com.znsd.zl.sys.sms.config.AliSmsConfig;
import com.znsd.zl.sys.sms.entity.SmsLogEntity;
import com.znsd.zl.sys.sms.service.ISmsLogService;
import com.znsd.zl.utils.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


/**
 * @ClassName AliSmsUtils
 * @Description 阿里短信服务工具类
 * @Author jaypdd
 * @Date 2020/8/18 15:13
 * @Version v1.0
 */
@Component
@Slf4j
public class AliSmsUtils {

	/**
	 * 短信配置类组件
	 */
	@Resource
	public AliSmsConfig config;

	/**
	 * 阿里短信接口调用客户端示例
	 */
	@Resource
	public IAcsClient acsClient;

	/**
	 * Redis缓存工具类
	 */
	@Resource
	public RedisUtils redisUtils;

	/**
	 * 系统短信日志业务层接口
	 */
	@Resource
	public ISmsLogService smsLogService;

	/**
	 * 发送短信验证码
	 * @param phone 手机号
	 * @param templateCode 短信模板id
	 * @return  发送成功 true 失败 false
	 */
	public boolean sendSmsCaptcha(String phone, String templateCode) {
		// 如果短信验证码发送，校验是否频繁操作
		if ( phone != null && isFrequentOperation(phone) ) {
			throw new RRException("频繁操作，请稍后重试");
		}

		// 获取随机数字短信验证码
		String code = generateVerificationCode();

		// 将当前手机验证码，以及短信发送时间，放入缓存
		Map<String, Object> map = new HashMap<String, Object>(3);
		map.put("code", code);
		map.put("sendTime", String.valueOf(System.currentTimeMillis()));
		redisUtils.set(phone, redisUtils.toJson(map), RedisUtils.SMS_CODE_EXPIRE);

		// 发送短信
		boolean sendStatus = sendSms(phone, code, templateCode);
		// 生成日志信息并保存
		this.generateSmsLog(phone, "短信验证码：" + code, sendStatus);

		return sendStatus;
	}

	/**
	 * 发送自定义内容短信
	 * @param phone     手机号码
	 * @param content   发送的短信内容
	 * @param templateCode  短信模板id
	 * @return  发送成功 true 失败 false
	 */
	public boolean sendContentSms(String phone, String content, String templateCode) {
		boolean sendStatus = sendSms(phone, content, templateCode);
		// 生成日志信息，并保存
		this.generateSmsLog(phone, content, sendStatus);
		return sendStatus;
	}

	/**
	 * 发送短信
	 * @param phone         发送的手机号码
	 * @param content       发送短信内容
	 * @param templateCode  模板id，不为空则使用，为空使用默认模板id
	 * @return
	 */
	public boolean sendSms(String phone, String content, String templateCode) {
		// 封装发送短信请求对象
		SendSmsRequest request = new SendSmsRequest();
		request.setPhoneNumbers(phone);
		request.setSignName(config.getSingName());
		request.setTemplateCode(templateCode == null ? config.getTemplateCode() : templateCode);
		request.setTemplateParam("{\"code\":\"" + content + "\"}");

		// 发送短信
		SendSmsResponse response = null;
		try {
			response = acsClient.getAcsResponse(request);
			if ( response.getCode() != null && Constant.SUCCESS_STATUS_CODE.equals(response.getCode())) {
				return true;
			}else{
				throw new RRException("发送失败，参数错误");
			}
		} catch (ServerException e) {
			e.printStackTrace();
		} catch (ClientException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 发送预约短信通知
	 * @param phone         发送的手机号码
	 * @param content       发送短信内容
	 * @param templateCode  模板id，不为空则使用，为空使用默认模板id
	 * @return
	 */
	public boolean sendReservedSms(String phone, String content, String templateCode) {
		// 封装发送短信请求对象
		SendSmsRequest request = new SendSmsRequest();
		request.setPhoneNumbers(phone);
		request.setSignName(config.getSingName());
		request.setTemplateCode(templateCode == null ? config.getTemplateCode() : templateCode);
		request.setTemplateParam("{\"name\":\"" + content + "\"}");

		// 发送短信
		SendSmsResponse response = null;
		try {
			response = acsClient.getAcsResponse(request);
			if ( response.getCode() != null && Constant.SUCCESS_STATUS_CODE.equals(response.getCode())) {
				this.generateSmsInformLog(phone, content, true,templateCode);
				return true;
			}else{
				this.generateSmsInformLog(phone, content, false,templateCode);
				throw new RRException("发送失败，参数错误");
			}
		} catch (ServerException e) {
			e.printStackTrace();
		} catch (ClientException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 校验验证码是否正确
	 * @param phone     手机号码
	 * @param captcha   验证码
	 * @return
	 */
	public boolean isCaptcha(String phone, String captcha) {
		// 获取缓存中的验证码信息
		Map<String, String> map = redisUtils.get(phone, Map.class);

		// 校验必备参数是否非空
		if ( map != null && phone != null && captcha != null ) {
			String code = map.get("code");
			if ( captcha.equals(code) ) {
				// 验证成功，将当前手机号设置禁用状态，并2分钟后自动取消
				redisUtils.delete(phone);
				return true;
			}
		}
		log.info("验证码不正确，captcha===>{}", captcha);
		return false;
	}

	/**
	 * 生成短信验证码
	 * @return  返回随机生成的六位数字验证码
	 */
	private String generateVerificationCode() {
		// 创建code可变字符对象，以及random随机对象
		StringBuilder code = new StringBuilder();
		Random random = new Random();

		// 循环6次，追加生成的随机单个数字
		int count = 6;
		while ( code.length() < count ) {
			code.append(random.nextInt(10));
		}
		return code.toString();
	}

	/**
	 * 判断手机号是否频繁操作
	 * @param phone 手机号
	 */
	private boolean isFrequentOperation(String phone) {
		if ( redisUtils.get(phone) != null ) {
			// 获取缓存中当前手机号码短信发送时间
			Map<String, String> map = redisUtils.get(phone, Map.class);
			// 将短信发送时间增加2分钟，如果时间大于或等于当前时间，则频繁操作
			long currentTime = Long.parseLong(map.get("sendTime")) + 120 * 1000;
			if ( currentTime >= System.currentTimeMillis() ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 生成短信日志
	 * @param phone      短信接收手机号
	 * @param content    发送的内容
	 * @param sendStatus 发送状态 true：成功 false：失败
	 */
	public void generateSmsLog(String phone, String content, boolean sendStatus) {
		// 封装短信日志
		SmsLogEntity smsLogEntity = new SmsLogEntity();
		smsLogEntity.setTemplateCode(config.getTemplateCode());
		smsLogEntity.setPhone(phone);
		smsLogEntity.setContent(content);
		smsLogEntity.setSendStatus(sendStatus ? 13 : 14);
		smsLogEntity.setSendTime(new Date());

		// 保存日志信息
		smsLogService.save(smsLogEntity);
		log.info("smsLogEntity===>{}", smsLogEntity);
	}

	/**
	 * 生成短信通知日志
	 * @param phone      短信接收手机号
	 * @param content    发送的内容
	 * @param sendStatus 发送状态 true：成功 false：失败
	 */
	public void generateSmsInformLog(String phone, String content, boolean sendStatus,String templateCode) {
		// 封装短信日志
		SmsLogEntity smsLogEntity = new SmsLogEntity();
		smsLogEntity.setTemplateCode(templateCode);
		smsLogEntity.setPhone(phone);
		smsLogEntity.setContent("预约用户的称呼："+content);
		smsLogEntity.setSendStatus(sendStatus ? 13 : 14);
		smsLogEntity.setSendTime(new Date());

		// 保存日志信息
		smsLogService.save(smsLogEntity);
		log.info("smsLogEntity===>{}", smsLogEntity);
	}

}



